
#include "PixClsfTools.h"

using namespace binary_ipfe_classification;

// [*] CBicExample

CBicExample::CBicExample()
{
	ParentFileSet = -1;
	FileIndex = -1;
	fIsPos = false;
	real_x = 0.0;
	real_y = 0.0;
	ipl_scale_x = 1.0;
	ipl_scale_y = 1.0;
}

CBicExample::CBicExample(const CImagePyramidPosition& ipp)
{
	ParentFileSet = -1;
	FileIndex = -1;
	fIsPos = false;
	real_x = ipp.xOld;
	real_y = ipp.yOld;
	ipl_scale_x = ipp.xScale;
	ipl_scale_y = ipp.yScale;
}

void CBicExample::ToIpp(CImagePyramidPosition& DstIpp) const
{
	DstIpp.InitNew(real_x, real_y, ipl_scale_x, ipl_scale_y);
}

bool CBicExample::InputFromBinaryFile(FILE* FIN)
{
	if (!CDataStructureTools::my_fread_single(FIN, ParentFileSet)) return false;
	if (!CDataStructureTools::my_fread_single(FIN, FileIndex)) return false;
	if (!CDataStructureTools::my_fread_single(FIN, fIsPos)) return false;
	if (!CDataStructureTools::my_fread_single(FIN, real_x)) return false;
	if (!CDataStructureTools::my_fread_single(FIN, real_y)) return false;
	if (!CDataStructureTools::my_fread_single(FIN, ipl_scale_x)) return false;
	if (!CDataStructureTools::my_fread_single(FIN, ipl_scale_y)) return false;
	return true;
}

void CBicExample::OutputToBinaryFile(FILE* FOUT) const
{
	CDataStructureTools::my_fwrite_single(FOUT, ParentFileSet);
	CDataStructureTools::my_fwrite_single(FOUT, FileIndex);
	CDataStructureTools::my_fwrite_single(FOUT, fIsPos);
	CDataStructureTools::my_fwrite_single(FOUT, real_x);
	CDataStructureTools::my_fwrite_single(FOUT, real_y);
	CDataStructureTools::my_fwrite_single(FOUT, ipl_scale_x);
	CDataStructureTools::my_fwrite_single(FOUT, ipl_scale_y);
}

bool CBicExample::InputFromStream(istream& inStream)
{
	if (inStream>>ParentFileSet>>FileIndex>>fIsPos>>real_x>>real_y>>ipl_scale_x>>ipl_scale_y)
		return true;
	else
		return false;
}

void CBicExample::OutputToStream(ostream& outStream) const
{
	outStream.precision(12);
	outStream<<'\t'<<ParentFileSet;
	outStream<<'\t'<<FileIndex;
	outStream<<'\t'<<fIsPos;
	outStream<<'\t'<<scientific<<real_x;
	outStream<<'\t'<<scientific<<real_y;
	outStream<<'\t'<<scientific<<ipl_scale_x;
	outStream<<'\t'<<scientific<<ipl_scale_y;
	outStream<<endl;
}

bool CBicExample::InputListFromBinaryFile(CSimpleTypeArray<CBicExample>& DstExampleList, string strFN_SrcExampleList)
{
	bool ret = true;
	size_t amount;

	DstExampleList.DeepClear();
	FILE* FIN = fopen(strFN_SrcExampleList.c_str(), "rb");
	ret &= CDataStructureTools::my_fread_single(FIN, amount);
	if (ret)
	{
		DstExampleList.Resize(amount);
		ret &= (amount == CDataStructureTools::my_fread(FIN, DstExampleList));\
		if (!ret)
			DstExampleList.DeepClear();
	}
	fclose(FIN);

	return ret;
}

void CBicExample::OutputListToBinaryFile(string strFN_DstExampleList, const CSimpleTypeArray<CBicExample>& SrcExampleList)
{
	FILE* FOUT = fopen(strFN_DstExampleList.c_str(), "wb");
	CDataStructureTools::my_fwrite_single(FOUT, SrcExampleList.Size);
	CDataStructureTools::my_fwrite(FOUT, SrcExampleList);
	fclose(FOUT);
}

bool CBicExample::InputListFromFile(CSimpleTypeArray<CBicExample>& DstExampleList, string strFN_SrcExampleList)
{
	bool ret = true;
	size_t i;
	size_t amount;

	ifstream inFile(strFN_SrcExampleList.c_str());

	ret &= !!(inFile>>amount);
	DstExampleList.Resize(amount);
	for ( i = 0; ret && i<amount; ++i )
		ret &= DstExampleList.pElement[i].InputFromStream(inFile);

	inFile.clear();
	inFile.close();

	if (!ret) DstExampleList.DeepClear();
	return ret;
}

void CBicExample::OutputListToFile(string strFN_DstExampleList, const CSimpleTypeArray<CBicExample>& SrcExampleList)
{
	ofstream outFile(strFN_DstExampleList.c_str());

	size_t i;
	outFile<<SrcExampleList.Size<<endl;
	for ( i = 0; i < SrcExampleList.Size; ++i )
		SrcExampleList.pElement[i].OutputToStream(outFile);

	outFile.clear();
	outFile.close();
}

// [*] CBicExampleConfig

CBicExampleConfig::CBicExampleConfig()
{
	PosExample_ImageExtent = 16;
	PosExample_xScale = 1.0;
	PosExample_yScale = 1.0;

	PosExample_ShakeRange_xCenter = 0.0;
	PosExample_ShakeRange_yCenter = 0.0;
	PosExample_ShakeRange_xScale = 1.00;
	PosExample_ShakeRange_yScale = 1.00;

	StdObjectTight_W = 32;
	StdObjectTight_H = 96;
	StdObjectScaleRatio_xTolerance = 0.5;
	StdObjectScaleRatio_yTolerance = 0.5;
	
	StdObjectContext_W = 64;
	StdObjectContext_H = 128;
	StdObjectCenter_xOffset = 0.5;
	StdObjectCenter_yOffset = 0.5;

	Scan_FitBox_Style = FIT_BOX_STYLE_MIN_SIZE;
	Scan_FitBox_Min_W = 1;
	Scan_FitBox_Min_H = 1;
}

void CBicExampleConfig::SetPosExampleBasicConfiguration(int ImageExtent, double xScale, double yScale)
{
	PosExample_ImageExtent = ImageExtent;
	PosExample_xScale = xScale;
	PosExample_yScale = yScale;
}

void CBicExampleConfig::SetPosExampleShakingConfiguration(double xCenter, double yCenter, double xScale, double yScale)
{
	PosExample_ShakeRange_xCenter = xCenter;
	PosExample_ShakeRange_yCenter = yCenter;
	PosExample_ShakeRange_xScale = xScale;
	PosExample_ShakeRange_yScale = yScale;
}

void CBicExampleConfig::SetStdObjectTightConfiguration(
	int Std_W, int Std_H,
	double xTolerance, double yTolerance
	)
{
	StdObjectTight_W = Std_W;
	StdObjectTight_H = Std_H;
	StdObjectScaleRatio_xTolerance = xTolerance;
	StdObjectScaleRatio_yTolerance = yTolerance;
}

void CBicExampleConfig::SetStdObjectContextConfiguration(
	int Std_W, int Std_H,
	double Center_xOffset, double Center_yOffset
	)
{
	StdObjectContext_W = Std_W;
	StdObjectContext_H = Std_H;
	StdObjectCenter_xOffset = Center_xOffset;
	StdObjectCenter_yOffset = Center_yOffset;
}

void CBicExampleConfig::SetScanningFitBoxConfiguration(
	int Style, int Min_W, int Min_H)
{
	Scan_FitBox_Style = Style;
	Scan_FitBox_Min_W = Min_W;
	Scan_FitBox_Min_H = Min_H;
}

//void CBicExampleConfig::SetScanningPixelSamplingConfiguration(
//	int SampleMargin,
//	double SampleRate)
//{
//	Scan_PixelSample_Margin = SampleMargin;
//	Scan_PixelSample_Rate = SampleRate;
//}

void CBicExampleConfig::AdjustScale(double& xScale, double& yScale) const
{
	double xyr = xScale / yScale;
	xScale = yScale * pow(xyr, StdObjectScaleRatio_xTolerance);
	yScale = yScale * pow(xyr, StdObjectScaleRatio_yTolerance);
}

void CBicExampleConfig::FixTightBoxScale(CRectBox<double>& DstTightBox, CRectBox<double> SrcTightBox) const
{
	DstTightBox = SrcTightBox;
	DstTightBox.x += DstTightBox.w * 0.5;
	DstTightBox.y += DstTightBox.h * 0.5;

	double sx = DstTightBox.w / StdObjectTight_W;
	double sy = DstTightBox.h / StdObjectTight_H;
	AdjustScale(sx, sy);
	DstTightBox.w = StdObjectTight_W * sx;
	DstTightBox.h = StdObjectTight_H * sy;

	DstTightBox.x -= DstTightBox.w * 0.5;
	DstTightBox.y -= DstTightBox.h * 0.5;
}

double CBicExampleConfig::GetIplScaleFromTightBox(CRectBox<double> SrcTightBox) const
{
	FixTightBoxScale(SrcTightBox, SrcTightBox);
	return sqrt((StdObjectTight_W * StdObjectTight_H) / (SrcTightBox.w * SrcTightBox.h));
}

void CBicExampleConfig::MakeContextBoxFromTightBox(CRectBox<double>& DstContextBox, CRectBox<double> SrcTightBox) const
{
	FixTightBoxScale(SrcTightBox, SrcTightBox);
	DstContextBox.w = SrcTightBox.w / StdObjectTight_W * StdObjectContext_W;
	DstContextBox.h = SrcTightBox.h / StdObjectTight_H * StdObjectContext_H;
	DstContextBox.x = SrcTightBox.x + SrcTightBox.w * 0.5 - DstContextBox.w * StdObjectCenter_xOffset;
	DstContextBox.y = SrcTightBox.y + SrcTightBox.h * 0.5 - DstContextBox.h * StdObjectCenter_yOffset;
}

void CBicExampleConfig::MakeTightBoxFromContextBox(CRectBox<double>& DstTightBox, CRectBox<double> SrcContextBox) const
{
	DstTightBox.w = SrcContextBox.w / StdObjectContext_W * StdObjectTight_W;
	DstTightBox.h = SrcContextBox.h / StdObjectContext_H * StdObjectTight_H;
	DstTightBox.x = SrcContextBox.x - DstTightBox.w * 0.5 + SrcContextBox.w * StdObjectCenter_xOffset;
	DstTightBox.y = SrcContextBox.y - DstTightBox.h * 0.5 + SrcContextBox.h * StdObjectCenter_yOffset;
	FixTightBoxScale(DstTightBox, DstTightBox);
}

void CBicExampleConfig::MakeExampleFromContextBox(CBicExample& DstExample, const CRectBox<double>& SrcContextBox) const
{
	DstExample.ipl_scale_x = StdObjectContext_W / SrcContextBox.w;
	DstExample.ipl_scale_y = StdObjectContext_H / SrcContextBox.h;
	DstExample.real_x = SrcContextBox.x + SrcContextBox.w * 0.5;
	DstExample.real_y = SrcContextBox.y + SrcContextBox.h * 0.5;
}

void CBicExampleConfig::MakeExampleFromTightBox(CBicExample& DstExample, const CRectBox<double>& SrcTightBox) const
{
	CRectBox<double> ContextBox;
	MakeContextBoxFromTightBox(ContextBox, SrcTightBox);
	MakeExampleFromContextBox(DstExample, ContextBox);
}

void CBicExampleConfig::MakeContextBoxFromExample(CRectBox<double>& DstContextBox, const CBicExample& SrcExample) const
{
	DstContextBox.w = StdObjectContext_W / SrcExample.ipl_scale_x;
	DstContextBox.h = StdObjectContext_H / SrcExample.ipl_scale_y;
	DstContextBox.x = SrcExample.real_x - DstContextBox.w * 0.5;
	DstContextBox.y = SrcExample.real_y - DstContextBox.h * 0.5;
}

void CBicExampleConfig::MakeTightBoxFromExample(CRectBox<double>& DstTightBox, const CBicExample& SrcExample) const
{
	CRectBox<double> ContextBox;
	MakeContextBoxFromExample(ContextBox, SrcExample);
	MakeTightBoxFromContextBox(DstTightBox, ContextBox);
}

void CBicExampleConfig::MakeTightBoxFromCenterAndIplScale(CRectBox<double>& DstTightBox, double CenterX, double CenterY, double IplScale) const
{
	DstTightBox.w = StdObjectTight_W / IplScale;
	DstTightBox.h = StdObjectTight_H / IplScale;
	DstTightBox.x = CenterX - DstTightBox.w * 0.5;
	DstTightBox.y = CenterY - DstTightBox.h * 0.5;
}

void CBicExampleConfig::MakeContextBoxFromCenterAndIplScale(CRectBox<double>& DstContextBox, double CenterX, double CenterY, double IplScale) const
{
	MakeTightBoxFromCenterAndIplScale(DstContextBox, CenterX, CenterY, IplScale);
	MakeContextBoxFromTightBox(DstContextBox, DstContextBox);
}

void CBicExampleConfig::MakeExampleFromCenterAndIplScale(CBicExample& DstExample, double CenterX, double CenterY, double IplScale) const
{
	CRectBox<double> ContextBox;
	MakeContextBoxFromCenterAndIplScale(ContextBox, CenterX, CenterY, IplScale);
	MakeExampleFromContextBox(DstExample, ContextBox);
}

void CBicExampleConfig::BuildPosExample(
	CBicExample& DstExample,
	int ParentFileSet, int FileIndex) const
{
	DstExample.ParentFileSet = ParentFileSet;
	DstExample.FileIndex = FileIndex;
	DstExample.fIsPos = true;
	DstExample.ipl_scale_x = 1.0 / PosExample_xScale;
	DstExample.ipl_scale_y = 1.0 / PosExample_yScale;
	DstExample.real_x = (PosExample_ImageExtent + StdObjectContext_W * 0.5) * PosExample_xScale;
	DstExample.real_y = (PosExample_ImageExtent + StdObjectContext_H * 0.5) * PosExample_yScale;
}

void CBicExampleConfig::GeneratePosExampleList(
	CSimpleTypeArray<CBicExample>& DstExampleList, bool fAppendMode,
	int ParentFileSet, int FileIndex,
	int Amount, bool fFixFirstUnshakeable, bool fUniform_XY_Scale) const
{
	if (!fAppendMode) DstExampleList.Clear();

	CBicExample oExample;
	CBicExample tExample;
	double ox, oy, sx, sy;

	BuildPosExample(oExample, ParentFileSet, FileIndex);
	int i;
	for ( i = 0; i < Amount; ++i )
	{
		tExample = oExample;
		if (i!=0 || !fFixFirstUnshakeable)
		{
			ox = StdObjectContext_W * PosExample_ShakeRange_xCenter / tExample.ipl_scale_x;
			oy = StdObjectContext_H * PosExample_ShakeRange_yCenter / tExample.ipl_scale_y;
			tExample.real_x += CMyRandom::NextDouble() * (ox + ox) - ox;
			tExample.real_y += CMyRandom::NextDouble() * (oy + oy) - oy;

			sx = log(PosExample_ShakeRange_xScale);
			sy = log(PosExample_ShakeRange_yScale);
			tExample.ipl_scale_x *= exp(CMyRandom::NextDouble() * (sx + sx) - sx);
			tExample.ipl_scale_y *= exp(CMyRandom::NextDouble() * (sy + sy) - sy);
			if (fUniform_XY_Scale)
				tExample.ipl_scale_x = tExample.ipl_scale_y = sqrt(tExample.ipl_scale_x * tExample.ipl_scale_y);
		}
		DstExampleList.PushBack(tExample);
	}
}

int CBicExampleConfig::GenerateNegExampleList(
	CSimpleTypeArray<CBicExample>& DstExampleList, bool fAppendMode,
	int Image_W, int Image_H,
	int PixelSampleMargin, double PixelSampleRate,
	int ScaleLevel, double ScaleFactor,
	int ParentFileSet, int FileIndex) const
{
	if (!fAppendMode) DstExampleList.Clear();

	int NegExample_ImageExtent = 0;

	int i, iw, ih, iiw, iih, ix, iy;
	double ss, tx, ty;
	ss = 1.0; for ( i = 0; i < ScaleLevel; ++i ) ss /= ScaleFactor;

	iw = (int)(Image_W * ss + 0.5);
	ih = (int)(Image_H * ss + 0.5);

	CBicExample tExample;
	tExample.ParentFileSet = ParentFileSet;
	tExample.FileIndex = FileIndex;
	tExample.fIsPos = false;
	tExample.ipl_scale_x = ss;
	tExample.ipl_scale_y = ss;

	int cw, ch;
	if (Scan_FitBox_Style == FIT_BOX_STYLE_CONTEXT)
	{
		cw = StdObjectContext_W;
		ch = StdObjectContext_H;
	}
	if (Scan_FitBox_Style == FIT_BOX_STYLE_TIGHT)
	{
		cw = StdObjectTight_W;
		ch = StdObjectTight_H;
	}
	if (Scan_FitBox_Style == FIT_BOX_STYLE_MIN_SIZE)
	{
		cw = ch = 0;
	}

	iw = (int)(Image_W * ss + 0.5);
	ih = (int)(Image_H * ss + 0.5);
	iiw = iw - cw - NegExample_ImageExtent * 2 + 1;
	iih = ih - ch - NegExample_ImageExtent * 2 + 1;
	if (iiw<1 || iih<1) return -1;
	if (Scan_FitBox_Style == FIT_BOX_STYLE_MIN_SIZE)
	{
		if (iiw < Scan_FitBox_Min_W) return -1;
		if (iih < Scan_FitBox_Min_H) return -1;
	}

	CRectBox<double> dBox;
	CPointInRectangleRandomSampler ips;
	ips.Work(iiw, iih, PixelSampleMargin, PixelSampleRate);
	const int* qspi;
	for ( qspi = ips.SampledPixelList.pElement, i = 0; i < (int)ips.SampledPixelList.Size; ++i, ++qspi )
	{
		ix = (*qspi)%iiw; iy = (*qspi)/iiw;
		tx = ix + 0.5 + cw * 0.5 + NegExample_ImageExtent;
		ty = iy + 0.5 + ch * 0.5 + NegExample_ImageExtent;
		if (1
			|| Scan_FitBox_Style == FIT_BOX_STYLE_TIGHT
			|| Scan_FitBox_Style == FIT_BOX_STYLE_MIN_SIZE
			)
		{
			dBox.w = StdObjectTight_W;
			dBox.h = StdObjectTight_H;
			dBox.x = tx - dBox.w * 0.5;
			dBox.y = ty - dBox.h * 0.5;
			MakeContextBoxFromTightBox(dBox, dBox);
			tx = dBox.x + dBox.w * 0.5;
			ty = dBox.y + dBox.h * 0.5;
		}
		tExample.real_x = tx / ss;
		tExample.real_y = ty / ss;
		DstExampleList.PushBack(tExample);
	}

	return (int)ips.SampledPixelList.Size;
}

// [*] CBicDetector

CBicDetector::CBicDetector()
{
	Scan_ScalingFactor = 1.2;
	Scan_SampleMargin = 7;
	Scan_SampleRate = 1.0;

	this->SetConfidenceThreshold(0.0);

	MeanShiftConfig.KernelConfig.dx = 8.0;
	MeanShiftConfig.KernelConfig.dy = 8.0;
	MeanShiftConfig.KernelConfig.dw = 1.3;
	MeanShiftConfig.KernelConfig.dh = 1.3;

	MeanShiftConfig.KernelConfig.scale = 1.0;
	MeanShiftConfig.KernelConfig.tfMode = CMeanShiftNMS::TFMODE_HARD;

	BicExampleConfig = CBicExampleConfig();

	pIPPFE = NULL;
	pImagePatchClassifier = NULL;
}

void CBicDetector::SetConfidenceThreshold(double ConfidenceThreshold)
{
	this->ConfidenceThreshold = ConfidenceThreshold;

	MeanShiftConfig.SetConfidenceThreshold(ConfidenceThreshold);
}

void CBicDetector::Init_IPPFE_and_Classifier(
	CImagePyramidPositionFeatureExtractor* pIPPFE,
	CBinaryClassifier* pImagePatchClassifier)
{
	this->pIPPFE = pIPPFE;
	this->pImagePatchClassifier = pImagePatchClassifier;
}

void CBicDetector::SetImage(string strFN_SrcImage)
{
	CExternalTools::myLoadImage(strFN_SrcImage, imgSrc);
	SetImage(imgSrc);
}

void CBicDetector::SetImage(const CImg<int>& imgSrc)
{
	W = imgSrc.width;
	H = imgSrc.height;
	this->imgSrc = imgSrc;
	//ZoomImage.myInit(imgSrc);
	pIPPFE->SetImage(imgSrc, "");
}

int CBicDetector::ProcessImageLayer_ByScale(CLayerResult& DstResult, double ipl_scale, bool fUseConfidenceThreshold) const
{
	CSimpleTypeArray<CBicExample> eList;
	int ret = BicExampleConfig.GenerateNegExampleList(
		eList, false,
		W, H, 
		Scan_SampleMargin, Scan_SampleRate,
		1, 1.0/ipl_scale,
		-1, -1);
	if (ret < 1) return ret;

	DstResult.ipl_scale = ipl_scale;

	int i_example;
	double tc;
	int tp, qx, qy;
	CRectBox<double> dBox;
	CCandidateDetection tDet;

	DstResult.LW = CMyMath::TranslateNumber_Round(W * ipl_scale, (int)0);
	DstResult.LH = CMyMath::TranslateNumber_Round(H * ipl_scale, (int)0);

	double gaussian_sigma = 1.0 * Scan_SampleMargin / sqrt(Scan_SampleRate);
	CKernel2D<double> Ker;
	CKernel2D<double>::GenerateGaussian(Ker, gaussian_sigma);

	int _Extent = Ker.kernelX.center + 1;
	int W2 = DstResult.LW + _Extent * 2;
	int H2 = DstResult.LH + _Extent * 2;

	CImg<double> imgTempConfidence(W2, H2); imgTempConfidence.fill(0.0);
	CImg<double> imgTempWeight(W2, H2); imgTempWeight.fill(0.0);
	CImg<double> imgTempDouble;

	DstResult.CanDetList.Clear();
	for ( i_example = 0; i_example < (int)eList.Size; ++i_example )
	{
		const CBicExample& tSIE = eList.pElement[i_example];

		tSIE.ToIpp(tDet.ipp);
		pIPPFE->SetQuery(tDet.ipp);
		pImagePatchClassifier->Classify(pIPPFE, tc, tp);

		dBox.w = BicExampleConfig.StdObjectContext_W;
		dBox.h = BicExampleConfig.StdObjectContext_H;
		dBox.x = tDet.ipp.xNew - dBox.w * 0.5;
		dBox.y = tDet.ipp.yNew - dBox.h * 0.5;
		BicExampleConfig.MakeTightBoxFromContextBox(dBox, dBox);
		qx = CMyMath::TranslateNumber_Floor(dBox.x + dBox.w * 0.5);
		qy = CMyMath::TranslateNumber_Floor(dBox.y + dBox.h * 0.5);
		//qx = (int)tDet.ipp.xNew; 
		//qy = (int)tDet.ipp.yNew;
		qx = (qx<0 ? 0 : (qx>=DstResult.LW ? DstResult.LW - 1 : qx));
		qy = (qy<0 ? 0 : (qy>=DstResult.LH ? DstResult.LH - 1 : qy));

		//imgTempConfidence.at(qx + _Extent, qy + _Extent) += exp(tc)/(1+exp(tc));
		imgTempConfidence.at(qx + _Extent, qy + _Extent) += tc;

		imgTempWeight.at(qx + _Extent, qy + _Extent) += 1.0;

		if (fUseConfidenceThreshold && tc<ConfidenceThreshold) continue;

		tDet.Confidence = tc;
		tDet.Tag = 0;
		DstResult.CanDetList.PushBack(tDet);
	} // i_example

	imgTempDouble = imgTempConfidence;
	Ker.Convolve(W2, H2, imgTempConfidence.data, imgTempDouble.data);
	imgTempDouble = imgTempWeight;
	Ker.Convolve(W2, H2, imgTempWeight.data, imgTempDouble.data);

	DstResult.imgConfidence.assign(DstResult.LW, DstResult.LH);
	CImg<int> imgVisit; imgVisit.assign(DstResult.LW, DstResult.LH);
	double* pc;
	int* pv;
	const double* qqc;
	const double* qqw;
	for ( qy = 0; qy < DstResult.LH; ++qy )
	{
		pc = DstResult.imgConfidence.data + qy * DstResult.LW;
		pv = imgVisit.data + qy * DstResult.LW;
		qqc = imgTempConfidence.data + _Extent + (_Extent + qy) * W2;
		qqw = imgTempWeight.data + _Extent + (_Extent + qy) * W2;
		for ( qx = 0; qx < DstResult.LW; ++qx )
		{
			if (*qqw > EPS)
			{
				*pc = *qqc / *qqw;
				*pv = qx + qy * DstResult.LW;
			}
			else
			{
				*pc = 0.0;
				*pv = -1;
			}
			++pc; ++pv; ++qqc; ++qqw;
		}
	}

	//for ( i_example = 0; i_example < (int)DstResult.CanDetList.Size; ++i_example )
	//{
	//	tDet = DstResult.CanDetList.pElement[i_example];
	//	qx = (int)tDet.ipp.xNew; qx = (qx<0 ? 0 : (qx>=DstResult.LW ? DstResult.LW - 1 : qx));
	//	qy = (int)tDet.ipp.yNew; qy = (qy<0 ? 0 : (qy>=DstResult.LH ? DstResult.LH - 1 : qy));
	//	tc = DstResult.imgConfidence.at(qx, qy);
	//	tc = tDet.Confidence - tc;
	//}

	CExternalTools::Expand_2D_SampledData(DstResult.imgConfidence, imgVisit);

	return ret;
}

int CBicDetector::ProcessImageLayer(CLayerResult& DstResult, int LayerIndex, bool fUseConfidenceThreshold) const
{
	return ProcessImageLayer_ByScale(DstResult, pow(Scan_ScalingFactor, -LayerIndex), fUseConfidenceThreshold);
}

void CBicDetector::DoNMS(
	CSimpleTypeArray<CDetectionWithScore>& DstDetectionList,
	const CSimpleTypeArray<CCandidateDetection>& SrcCanDetList,
	bool fToTightBox) const
{
	int i;
	CMeanShiftNMS msNMS;
	CDetectionWithScore tDet;
	CSimpleTypeArray<CCandidateDetection> ReducedDetList;

	msNMS.myInit(MeanShiftConfig, NULL, NULL);
	msNMS.DoNMS(ReducedDetList, SrcCanDetList);
	DstDetectionList.Resize(ReducedDetList.Size);
	for ( i = 0; i < (int)ReducedDetList.Size; ++i )
	{
		const CCandidateDetection& ttt = ReducedDetList.pElement[i];
		BicExampleConfig.MakeContextBoxFromExample(tDet.Detection, ttt.ipp);
		if (fToTightBox)
			BicExampleConfig.MakeTightBoxFromContextBox(tDet.Detection, tDet.Detection);
		tDet.Score = ttt.Confidence;
		tDet.fIsMatched = false;
		DstDetectionList.pElement[i] = tDet;
	}
	sort(DstDetectionList.Begin(), DstDetectionList.End());
}

// [*] CBicExampleFeatureDataSet

CBicExampleFeatureDataSet::CBicExampleFeatureDataSet()
{
	strFN_Pfx_ImageCacheHashName = "";
	pList_BicExampleParentFileNameSet = NULL;
	pIPPFE = NULL;
	_fSharedIPPFE = false;
}

CBicExampleFeatureDataSet::~CBicExampleFeatureDataSet()
{
	if (!_fSharedIPPFE) CDataStructureTools::MyRelease_Single(this->pIPPFE);
}

void CBicExampleFeatureDataSet::InitIPPFE(CImagePositionFeatureExtractor* pPrototypeIPFE, int CacheSize)
{
	InitIPPFE(new CImagePyramidPositionFeatureExtractor(pPrototypeIPFE->myClone(), CacheSize), false);
}

void CBicExampleFeatureDataSet::InitIPPFE(CImagePyramidPositionFeatureExtractor* pInitializedIPPFE, bool fShared)
{
	if (!_fSharedIPPFE) CDataStructureTools::MyRelease_Single(this->pIPPFE);
	this->pIPPFE = pInitializedIPPFE;
	_fSharedIPPFE = fShared;	
	_LastParentFileSet = _LastFileIndex = _LastNode = -1;
}

void CBicExampleFeatureDataSet::InitBicExampleList(string strFN_ExampleList)
{
	char strTemp[10001];
	sprintf_s(strTemp, "Loading Example List \"%s\" ...", strFN_ExampleList.c_str());
	CExternalTools::ConsoleTools::ClearCurrentLine();
	cout<<strTemp;

	CBicExample::InputListFromFile(ExampleList, strFN_ExampleList);
	this->ExampleAmount = (int)ExampleList.Size;

	_ImageHandle = 0;
	_LastParentFileSet = _LastFileIndex = _LastNode = -1;

	sprintf_s(strTemp, "Loaded Example List \"%s\" ;", strFN_ExampleList.c_str());
	CExternalTools::ConsoleTools::ClearCurrentLine();
	cout<<strTemp<<endl;
}

void CBicExampleFeatureDataSet::InitBicExampleList_Binary(string strFN_ExampleList)
{
	char strTemp[10001];
	sprintf_s(strTemp, "Loading Example List \"%s\" ...", strFN_ExampleList.c_str());
	CExternalTools::ConsoleTools::ClearCurrentLine();
	cout<<strTemp;

	CBicExample::InputListFromBinaryFile(ExampleList, strFN_ExampleList);
	this->ExampleAmount = (int)ExampleList.Size;

	_ImageHandle = 0;
	_LastParentFileSet = _LastFileIndex = _LastNode = -1;

	sprintf_s(strTemp, "Loaded Example List \"%s\" ;", strFN_ExampleList.c_str());
	CExternalTools::ConsoleTools::ClearCurrentLine();
	cout<<strTemp<<endl;
}

void CBicExampleFeatureDataSet::InitBicExampleParentFileNameSetList(
	CSimpleTypeArray<CBicExampleParentFileNameSet>* pList_BicExampleParentFileNameSet,
	string strFN_Pfx_ImageCacheHashName)
{
	this->pList_BicExampleParentFileNameSet = pList_BicExampleParentFileNameSet;
	this->strFN_Pfx_ImageCacheHashName = strFN_Pfx_ImageCacheHashName;
}

void CBicExampleFeatureDataSet::SetQuery(int NodeIndex)
{
	if (NodeIndex<0 || NodeIndex>=ExampleAmount) return;

	if (pIPPFE!=NULL && this->_ImageHandle!=pIPPFE->ImageHandle)
	{
		//cout<<_ImageHandle<<" "<<pIPPFE->ImageHandle<<endl;
		_ImageHandle = 0;
		_LastParentFileSet = _LastFileIndex = _LastNode = -1;
	}

	if (NodeIndex == _LastNode) return;

	_LastNode = NodeIndex;

	const CBicExample& tExample = ExampleList.pElement[NodeIndex];

	if (tExample.ParentFileSet!=_LastParentFileSet || tExample.FileIndex!=_LastFileIndex)
	{
		_LastParentFileSet = tExample.ParentFileSet;
		_LastFileIndex = tExample.FileIndex;

		string strFN_Src = "";
		if (pList_BicExampleParentFileNameSet != NULL)
		{
			int i;
			for ( i = 0; i < (int)pList_BicExampleParentFileNameSet->Size; ++i )
			{
				const CBicExampleParentFileNameSet& CurrentFileSet = pList_BicExampleParentFileNameSet->pElement[i];
				if (_LastParentFileSet == CurrentFileSet.SetIndex)
				{
					if (_LastFileIndex>=0 && _LastFileIndex<(int)CurrentFileSet.FileNameList.Size)
						strFN_Src = CurrentFileSet.FileNameList.pElement[_LastFileIndex];
					break;
				}
			}
		}
		if (strFN_Src == "")
		{
			_ImageHandle = 0;
			_LastParentFileSet = _LastFileIndex = _LastNode = -1;
			//TODO
			return;
		}

		CImg<int> imgSrc;
		char strTemp[10001];

		sprintf_s(strTemp, "%s%d.%04d", strFN_Pfx_ImageCacheHashName.c_str(), _LastParentFileSet, _LastFileIndex);
		CExternalTools::myLoadImage(strFN_Src, imgSrc);

		if (this->pIPPFE != NULL)
			_ImageHandle = this->pIPPFE->SetImage(imgSrc, strTemp);
		else
			_ImageHandle = 0;
	}

	CImagePyramidPosition ipp;
	ipp.InitNew(tExample.real_x, tExample.real_y, tExample.ipl_scale_x, tExample.ipl_scale_y);
	if (this->pIPPFE != NULL) this->pIPPFE->SetQuery(ipp);
}

double CBicExampleFeatureDataSet::GetFeature(int FeatureIndex)
{
	if (this->pIPPFE==NULL || _LastNode<0 || _LastNode>=ExampleAmount || FeatureIndex<0 || FeatureIndex>=this->pIPPFE->Dim) return 0.0;

	return this->pIPPFE->GetFeature(FeatureIndex);
}

int CBicExampleFeatureDataSet::GetFeatureDimension()
{
	return (this->pIPPFE==NULL ? 0 : this->pIPPFE->GetFeatureDimension());
}

int CBicExampleFeatureDataSet::GetExampleAmount()
{
	return ExampleAmount;
}

int CBicExampleFeatureDataSet::GetExampleLabel(int NodeIndex)
{
	if (NodeIndex<0 || NodeIndex>=ExampleAmount) return -1;
	return (ExampleList.pElement[NodeIndex].fIsPos ? +1 : -1);
}

double CBicExampleFeatureDataSet::GetExampleInitialWeight(int NodeIndex)
{
	return 1.0;
}

double CBicExampleFeatureDataSet::GetExampleFeature(int NodeIndex, int FeatureIndex)
{
	if (NodeIndex<0 || NodeIndex>=ExampleAmount) return 0.0;
	SetQuery(NodeIndex);

	//return 0.0;

	return GetFeature(FeatureIndex);
}

size_t CBicExampleFeatureDataSet::GetMemoryUsage() const
{
	return 0 // + CLabeledDataSetForClassification::GetMemoryUsage()
		+ sizeof(int) * 5
		+ sizeof(CImagePyramidPositionFeatureExtractor*)
		+ sizeof(pList_BicExampleParentFileNameSet)
		+ ExampleList.GetMemoryUsage()
		+ (pIPPFE==NULL ? 0 : pIPPFE->GetMemoryUsage());
}

